#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/limits.h>
#include <dirent.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>

#define MAX_THREAD_NUMS 10
#define gettid() syscall(SYS_gettid)

void* ThreadFun(void* arg);
blkcnt_t traverseDir(char* entryName);
static char path[MAX_THREAD_NUMS][PATH_MAX];

int main(int argc, char* argv[])
{
    int threadNum = 0;
    pthread_t threads[MAX_THREAD_NUMS];
    if (argc != 3) {
        printf("Uasge: %s <path> <thread_num>\n", argv[0]);
        return 1;
    }

    threadNum = atoi(argv[2]);
    if (threadNum > MAX_THREAD_NUMS) {
        printf("thread num must less than %d\n", MAX_THREAD_NUMS);
        return 1;
    }

    for (int i = 0; i < threadNum; i++) { 
        sprintf(path[i], "%s_file_dir%d", argv[1], i+1);
        int rc = pthread_create(&threads[i], NULL, ThreadFun, (void*)path[i]);
        if (rc) {
            printf("Failed to create pthread %d\n", i);
            return 0;
        }
    }

    for (int i = 0; i < threadNum; i++) {
        int rc = pthread_join(threads[i], NULL);
        if (rc != 0) {
            printf("Failed to pthread join %d\n", i);
            return 0;
        }
    }

    return 0;
}

void* ThreadFun(void* arg)
{
    blkcnt_t totalSize = 0;
    char* path = (char*)arg;
    
    totalSize = traverseDir(path);
    printf("pid:%lu tid:%lu total: %ld path:%s\n",getpid(), gettid(), totalSize, path);
    return NULL;
}

blkcnt_t traverseDir(char* entryName)
{
    DIR* dir;
    struct dirent* newEntry;
    blkcnt_t totalSize = 0;

    if (entryName == NULL) {
        printf("path is null\n");
        return 0;
    }

    dir = opendir(entryName);
    if (!dir) {
        perror(entryName);
        return 0;
    }

    while (newEntry = readdir(dir)) {
        if (strcmp(newEntry->d_name, ".") == 0 || strcmp(newEntry->d_name, "..") == 0) {
            continue;
        }

        if (newEntry->d_type == DT_DIR) {
            struct stat st;
            char path[PATH_MAX];

            sprintf(path, "%s/%s", entryName, newEntry->d_name);
            if (lstat(path, &st)) {
                perror(path);
                return 0;
            }

            totalSize += st.st_size;
            totalSize += traverseDir(path);
        } else {
            // file
            struct stat st;
            char path[PATH_MAX];
            sprintf(path, "%s/%s", entryName, newEntry->d_name);

            if (lstat(path, &st)) {
                perror(path);
                return 0;
            }
            // totalSize += st.st_blocks;
            totalSize += st.st_size;
            // printf("total=%ld size=%ld file=%s \n", totalSize, st.st_size, path);
        }
    }

    return totalSize;
}
